////////////////////////////////////////////////
// -- Inscript                                //
// by Hurricaaane (Ha3)                       //
//                                            //
// http://www.youtube.com/user/Hurricaaane    //
//--------------------------------------------//
// Main file, with core functions             //
////////////////////////////////////////////////

if not inscript then inscript = {} end

inscript_dat = {}

inscript_dat.PANEL_Types = {}
inscript_dat.PANEL_Constructors = {}
inscript_dat.PANEL_ConvarSuffixes = {}

inscript_dat.STOR_Smoothers = {}

-- Initialize
function inscript.LoadAllPlugins()
	inscript_plugin.RemoveAll()

	local path = INSCRIPT_PLUGINDIR
	for _,file in pairs(file.FindInLua(path.."*_plugin.lua")) do
		PLUGIN = {}
		PLUGIN.HOOK = {}
		
		include(path..file)
		
		local sKeyword = string.Replace(file, "_plugin.lua", "")
		inscript_plugin.Register(sKeyword, PLUGIN)
		
		PLUGIN = nil
	end
	
	inscript_plugin.SortNamesTable()
	inscript_plugin.ForthBarnstars()
	
	if INSCRIPT_DEBUG then
		local stNames = inscript_plugin.GetNamesTable()
		
		print(INSCRIPT_NAME .. " >> Registered Plugins : ")
		for k,name in pairs( stNames ) do
			Msg("["..name.."] ")
		end
		Msg("\n")
	end
	
	if tonumber(inscript.GetVar("inscript_core_enable") or 0) > 0 then inscript.MountDesiredPlugins() end
end

function inscript.MountDesiredPlugins()
	local stNames = inscript_plugin.GetNamesTable()
	
	for _,sName in pairs( stNames ) do
		if tonumber( inscript.GetVar("inscript_plugin_" .. sName) or 0 ) > 0 then
			inscript_plugin.GetPluginObject( sName ):Mount()
		else
			inscript_plugin.GetPluginObject( sName ):Unmount()
		end
	end
end

function inscript.MountPlugin( sName )
	if not sName or not table.HasValue( inscript_plugin.GetNamesTable() , sName ) then return end
	
	local plugin = inscript_plugin.GetPluginObject( sName )
	plugin:Mount( )
end

function inscript.MountPluginCommand( player, command, stName )
	inscript.MountPlugin( stName[1] )
end

function inscript.UnmountPlugin( sName )
	if not sName or not table.HasValue( inscript_plugin.GetNamesTable() , sName ) then return end
	
	local plugin = inscript_plugin.GetPluginObject( sName )
	plugin:Unmount( )
end

function inscript.UnmountPluginCommand( player, command, stName )
	inscript.UnmountPlugin( stName[1] )
end

function inscript.TogglePlugin( sName )
	if not sName or not table.HasValue( inscript_plugin.GetNamesTable() , sName ) then return end
	
	local plugin = inscript_plugin.GetPluginObject( sName )
	if plugin:IsPerform( ) or not plugin:IsMounted( ) then
		plugin:Mount( )
	else
		plugin:Unmount( )
	end
end

function inscript.TogglePluginCommand( player, command, stName )
	inscript.TogglePlugin( stName[1] )
end

function inscript.ReloadAllPluginsCommand( player, command, stName )
	inscript.LoadAllPlugins()
	if inscript.DestroyMenu then inscript.DestroyMenu( ) end
end


function inscript.RevertPlugin( sName )
	if not sName or not table.HasValue( inscript_plugin.GetNamesTable() , sName ) then return end
	
	local plugin = inscript_plugin.GetPluginObject( sName )
	for key,def in pairs(plugin:GetPluginDefaultsTable()) do
		--print(key .. " = " .. def)
		inscript.SetVar(key, def)
	end
end

function inscript.RevertPluginCommand( player, command, stName )
	inscript.RevertPlugin( stName[1] )
end

-- Useful functions for user

function inscript.StringNiceNameTransform( stringInput )
	local stringParts = string.Explode("_",stringInput)
	local stringOutput = ""
	for k,part in pairs(stringParts) do
		local len = string.len(part)
		if (len == 1) then
			stringOutput = stringOutput .. string.upper(part)
		elseif (len > 1) then
			stringOutput = stringOutput .. string.Left(string.upper(part),1) .. string.Right(part,len-1)
		end
		if (k ~= #stringParts) then stringOutput = stringOutput .. " " end
	end
	return stringOutput
end


function inscript.PrimeColorFromTable( cColor, tHyb )
	cColor.r = tHyb[1]
	cColor.g = tHyb[2]
	cColor.b = tHyb[3]
	cColor.a = tHyb[4] or 255
end

-- Derma Panel Constructors

function inscript.Data_IsMounted( stData )
	return stData._plugin and stData._plugin.IsMounted and stData._plugin:IsMounted() or false
end

function inscript.ParamTypeExists( sType )
	return table.HasValue( inscript_dat.PANEL_Types , string.lower(sType) )
end

function inscript.RegisterPanelConstructor( sType, fConstructor, stConvarSuffixes )
	sType = string.lower(sType)
	if inscript.ParamTypeExists( sType ) then return end
	
	inscript_dat.PANEL_Constructors[sType] = fConstructor
	inscript_dat.PANEL_ConvarSuffixes[sType] = stConvarSuffixes or nil
	table.insert( inscript_dat.PANEL_Types, sType)
	
	if INSCRIPT_DEBUG then print(INSCRIPT_NAME .. " > Registered Panel Constructor : "..sType) end
end

function inscript.BuildParamConvars( sType, sFullConvarName, sDefault )
	sType = string.lower(sType)
	if not inscript.ParamTypeExists( sType ) then return false end
	
	if inscript_dat.PANEL_ConvarSuffixes[sType] == nil then
		inscript.CreateVar(sFullConvarName, tostring(sDefault), true, false)
		if INSCRIPT_DEBUG then print(INSCRIPT_NAME .. " > Added Var : "..sFullConvarName.." = "..tostring(sDefault)) end
		
	elseif type(inscript_dat.PANEL_ConvarSuffixes[sType]) == "table" then
		for k,suffix in pairs( inscript_dat.PANEL_ConvarSuffixes[sType] ) do
			inscript.CreateVar(sFullConvarName .. "_" .. suffix, tostring(sDefault[k] or sDefault[1] or sDefault), true, false)
			if INSCRIPT_DEBUG then print(INSCRIPT_NAME .. " > Added Var : "..sFullConvarName .. "_" .. suffix.." = "..tostring(sDefault[k] or sDefault[1] or sDefault)) end
		end
		
	else -- Could be a "noconvars" that is a string, and so exit code
		return false
		
	end
	
	return true
end

function inscript.GetParamSuffixes( sType )
	sType = string.lower(sType)
	if not inscript.ParamTypeExists( sType ) then return end
	
	return inscript_dat.PANEL_ConvarSuffixes[sType]
end

function inscript.GetParamConvars( sType, sFullConvarName )
	sType = string.lower(sType)
	if not inscript.ParamTypeExists( sType ) then return end
	
	local myConvars = {}
	
	if inscript_dat.PANEL_ConvarSuffixes[sType] == nil then
		table.insert(myConvars, sFullConvarName)
		
	elseif type(inscript_dat.PANEL_ConvarSuffixes[sType]) == "table" then
		for k,suffix in pairs( inscript_dat.PANEL_ConvarSuffixes[sType] ) do
			table.insert(myConvars, sFullConvarName .. "_" .. suffix)
		end
	end
	return myConvars
end

function inscript.BuildParamPanel( sFullConvarName, stData )
	if not inscript.ParamTypeExists( stData.Type ) then return end
	
	return inscript_dat.PANEL_Constructors[stData.Type](sFullConvarName , stData)
end

function inscript.InitializeGenericConstructors()
	inscript.RegisterPanelConstructor( "label" , function( sFullConvarName, stData )	
		local myPanel = vgui.Create("DLabel")
		myPanel:SetText( stData.Text or "<Error : no text !>" )
		return myPanel
	end , "noconvars" )
	inscript.RegisterPanelConstructor( "checkbox" , function( sFullConvarName, stData )
		local myPanel = vgui.Create( "DCheckBoxLabel" )
		myPanel:SetText( stData.Text or "<Error : no text !>" )
		myPanel:SetConVar( sFullConvarName )
		myPanel.OnChange = function( ... )
			if inscript.Data_IsMounted( stData ) and stData.OnChange then
				stData.OnChange( ... )
			end
		end
		return myPanel 
	end )
	inscript.RegisterPanelConstructor( "slider" , function( sFullConvarName, stData )	
		local myPanel = vgui.Create( "DNumSlider" )
		myPanel:SetText( stData.Text or "<Error : no text !>" )
		myPanel:SetMin( tonumber(stData.Min or 0) )
		myPanel:SetMax( tonumber(stData.Max or ((stData.Min or 0) + 1)) )
		myPanel:SetDecimals( tonumber(stData.Decimals or 0) )
		myPanel:SetConVar( sFullConvarName )
		myPanel.OnValueChanged = function( ... )
			if inscript.Data_IsMounted( stData ) and stData.OnChange then
				stData.OnChange( ... )
			end
		end
		return myPanel 
	end )
	inscript.RegisterPanelConstructor( "color" , function( sFullConvarName, stData )	
		local myPanel = vgui.Create("CtrlColorExtended")
		myPanel:SetConVarR(sFullConvarName.."_r")
		myPanel:SetConVarG(sFullConvarName.."_g")
		myPanel:SetConVarB(sFullConvarName.."_b")
		myPanel:SetConVarA(sFullConvarName.."_a")
		-- TODO : Add update call ...
		return myPanel 
	end , {"r","g","b","a"})
	inscript.RegisterPanelConstructor( "textentry" , function( sFullConvarName, stData )	
		local myPanel = vgui.Create("DTextEntry")
		myPanel:SetConVar(sFullConvarName)
		myPanel:SetUpdateOnType( stData.UpdateOnType and true or false )
		myPanel.OnValueChange = function( ... )
			if inscript.Data_IsMounted( stData ) and stData.OnChange then
				stData.OnChange( ... )
			end
		end
		myPanel.OnEnter = function( ... )
			if inscript.Data_IsMounted( stData ) and stData.OnEnter then
				stData.OnEnter( ... )
			end
		end
		return myPanel 
	end )
	inscript.RegisterPanelConstructor( "button" , function( sFullConvarName, stData )	
		local myPanel = vgui.Create("DButton")
		myPanel:SetText( stData.Text or "<Error : no text !>" )
		myPanel.DoClick = function( ... )
			if inscript.Data_IsMounted( stData ) and stData.DoClick then
				stData.DoClick( ... )
			end
		end
		myPanel.DoRightClick = function( ... )
			if inscript.Data_IsMounted( stData ) and stData.DoRightClick then
				stData.DoRightClick( ... )
			end
		end
		return myPanel
	end , "noconvars" )
end

-- Think Hook for WatchParameters.
function inscript.Think_WatchParameters()
	local plugins = inscript_plugin.GetAllPlugins( )
	
	for k,plugin in pairs(plugins) do
		
		if plugin:IsMounted() and plugin._WatchParameters then
			if INSCRIPT_DEBUG == 2 then print(plugin:GetDisplayName() .." seems to have a watch.") end
			
			for sParameterName,bHasAlreadyChanged in pairs( plugin._WatchParameters ) do
				if not bHasAlreadyChanged then
					local currentState = plugin:GetParameterSettings( sParameterName, true )
					local bFoundChange = false
					
					if type(currentState) == "table" then
						local iter = 1
						repeat
							bFoundChange = currentState[iter] ~= plugin._WatchParametersCache[sParameterName][iter]
							
							iter = iter + 1
						until (bFoundChange or (iter > #currentState))
						
					else -- Must be a hybrid
						if INSCRIPT_DEBUG == 2 then print("COMPAR : ".. currentState .. " < - > " .. plugin._WatchParametersCache[sParameterName]) end
						bFoundChange = currentState ~= plugin._WatchParametersCache[sParameterName]
						
					end
					plugin._WatchParameters[sParameterName] = bFoundChange
					
					if not bFoundChange then
						plugin._WatchParametersCache[sParameterName] = currentState
					end
					
					if bFoundChange then
						if INSCRIPT_DEBUG == 2 then print(plugin:GetDisplayName() .."::".. sParameterName .." seems to have changed.") end
					end
				end
				
			end
			
		end
		
	end
	
end

-- Load
function inscript.PluginAutoComplete(commandName,args)
	local myTable = inscript_plugin.GetNamesTable()
	for k,v in pairs( myTable ) do
		myTable[k] = commandName .. " " .. v
	end
	return myTable
end

function inscript.Mount()
	print("")
	print("[ Mounting " .. INSCRIPT_NAME .. " ... ]")
	
	inscript.CreateVar("inscript_core_enable", "1", true, false)
	
	if inscript.MountMenu then
		inscript.MountMenu()
	end

	concommand.Add("inscript_call_reloadpluginlist", inscript.ReloadAllPluginsCommand)
	concommand.Add("inscript_call_toggleplugin", inscript.TogglePluginCommand, inscript.PluginAutoComplete)
	concommand.Add("inscript_call_mountplugin", inscript.MountPluginCommand, inscript.PluginAutoComplete)
	concommand.Add("inscript_call_unmountplugin", inscript.UnmountPluginCommand, inscript.PluginAutoComplete)
	concommand.Add("inscript_call_revertplugin", inscript.RevertPluginCommand, inscript.PluginAutoComplete)
	hook.Add("Think", "inscript_Think_WatchParameters", inscript.Think_WatchParameters)
	
	inscript.InitializeGenericConstructors()
	inscript.LoadAllPlugins( )
	
	print("[ " .. INSCRIPT_NAME .. " is now mounted. ]")
	print("")
	
end

function inscript.Unmount()
	print("")
	print("] Unmounting " .. INSCRIPT_NAME .. " ... [")
	inscript_plugin.RemoveAll()
	
	if inscript.UnmountMenu then
		inscript.UnmountMenu()
	end

	concommand.Remove("inscript_call_reloadpluginlist")
	concommand.Remove("inscript_call_toggleplugin")
	concommand.Remove("inscript_call_mountplugin")
	concommand.Remove("inscript_call_unmountplugin")
	concommand.Remove("inscript_call_revertplugin")
	hook.Remove("Think", "inscript_Think_WatchParameters")
	
	table.Empty(inscript_dat)
	table.Empty(inscript)
	
	inscript_dat = nil
	inscript = nil
	
	print("] " .. INSCRIPT_NAME .. " has been unmounted. [")
	print("")
	
end
